home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gstext.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  16.7 KB  |  579 lines

  1. /* Copyright (C) 1998, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gstext.c,v 1.3.2.1 2000/10/26 12:45:11 igorm Exp $ */
  20. /* Driver text interface support */
  21. #include "memory_.h"
  22. #include "gstypes.h"
  23. #include "gdebug.h"
  24. #include "gserror.h"
  25. #include "gserrors.h"
  26. #include "gsmemory.h"
  27. #include "gsstruct.h"
  28. #include "gstypes.h"
  29. #include "gxdevcli.h"
  30. #include "gxdcolor.h"        /* for gs_state_color_load */
  31. #include "gxfont.h"        /* for init_fstack */
  32. #include "gxpath.h"
  33. #include "gxtext.h"
  34. #include "gzstate.h"
  35.  
  36. /* GC descriptors */
  37. public_st_gs_text_params();
  38. public_st_gs_text_enum();
  39.  
  40. private 
  41. ENUM_PTRS_WITH(text_params_enum_ptrs, gs_text_params_t *tptr) return 0;
  42. case 0:
  43. if (tptr->operation & TEXT_FROM_STRING) {
  44.     return ENUM_CONST_STRING2(tptr->data.bytes, tptr->size);
  45. }
  46. if (tptr->operation & TEXT_FROM_BYTES)
  47.     return ENUM_OBJ(tptr->data.bytes);
  48. if (tptr->operation & TEXT_FROM_CHARS)
  49.     return ENUM_OBJ(tptr->data.chars);
  50. if (tptr->operation & TEXT_FROM_GLYPHS)
  51.     return ENUM_OBJ(tptr->data.glyphs);
  52. return ENUM_OBJ(NULL);
  53. case 1:
  54. return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
  55.         tptr->x_widths : NULL);
  56. case 2:
  57. return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
  58.         tptr->y_widths : NULL);
  59. ENUM_PTRS_END
  60. private RELOC_PTRS_WITH(text_params_reloc_ptrs, gs_text_params_t *tptr)
  61. {
  62.     if (tptr->operation & TEXT_FROM_STRING) {
  63.     gs_const_string str;
  64.  
  65.     str.data = tptr->data.bytes;
  66.     str.size = tptr->size;
  67.     RELOC_CONST_STRING_VAR(str);
  68.     tptr->data.bytes = str.data;
  69.     } else if (tptr->operation & TEXT_FROM_BYTES)
  70.     RELOC_OBJ_VAR(tptr->data.bytes);
  71.     else if (tptr->operation & TEXT_FROM_CHARS)
  72.     RELOC_OBJ_VAR(tptr->data.chars);
  73.     else if (tptr->operation & TEXT_FROM_GLYPHS)
  74.     RELOC_OBJ_VAR(tptr->data.glyphs);
  75.     if (tptr->operation & TEXT_REPLACE_WIDTHS) {
  76.     RELOC_OBJ_VAR(tptr->x_widths);
  77.     RELOC_OBJ_VAR(tptr->y_widths);
  78.     }
  79. }
  80. RELOC_PTRS_END
  81.  
  82. private ENUM_PTRS_WITH(text_enum_enum_ptrs, gs_text_enum_t *eptr)
  83. {
  84.     index -= 7;
  85.     if (index <= eptr->fstack.depth)
  86.     ENUM_RETURN(eptr->fstack.items[index].font);
  87.     index -= eptr->fstack.depth + 1;
  88.      return ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index);
  89. }
  90. case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
  91. ENUM_PTR3(1, gs_text_enum_t, pis, orig_font, path);
  92. ENUM_PTR3(4, gs_text_enum_t, pdcolor, pcpath, current_font);
  93. ENUM_PTRS_END
  94.  
  95. private RELOC_PTRS_WITH(text_enum_reloc_ptrs, gs_text_enum_t *eptr)
  96. {
  97.     int i;
  98.  
  99.     RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
  100.     eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
  101.     RELOC_PTR3(gs_text_enum_t, pis, orig_font, path);
  102.     RELOC_PTR3(gs_text_enum_t, pdcolor, pcpath, current_font);
  103.     for (i = 0; i <= eptr->fstack.depth; i++)
  104.     RELOC_PTR(gs_text_enum_t, fstack.items[i].font);
  105. }
  106. RELOC_PTRS_END
  107.  
  108. /* Begin processing text. */
  109. int
  110. gx_device_text_begin(gx_device * dev, gs_imager_state * pis,
  111.              const gs_text_params_t * text, gs_font * font,
  112.              gx_path * path,    /* unless DO_NONE & !RETURN_WIDTH */
  113.              const gx_device_color * pdcolor,    /* DO_DRAW */
  114.              const gx_clip_path * pcpath,    /* DO_DRAW */
  115.              gs_memory_t * mem, gs_text_enum_t ** ppte)
  116. {
  117.     if (TEXT_PARAMS_ARE_INVALID(text))
  118.     return_error(gs_error_rangecheck);
  119.     {
  120.     gx_path *tpath =
  121.         ((text->operation & TEXT_DO_NONE) &&
  122.          !(text->operation & TEXT_RETURN_WIDTH) ? 0 : path);
  123.     const gx_device_color *tcolor =
  124.         (text->operation & TEXT_DO_DRAW ? pdcolor : 0);
  125.     const gx_clip_path *tcpath =
  126.         (text->operation & TEXT_DO_DRAW ? pcpath : 0);
  127.     return dev_proc(dev, text_begin)
  128.         (dev, pis, text, font, tpath, tcolor, tcpath, mem, ppte);
  129.     }
  130. }
  131.  
  132. /* 
  133.  * Initialize a newly created text enumerator.  Implementations of
  134.  * text_begin must call this just after allocating the enumerator.
  135.  */
  136. private int
  137. gs_text_enum_init_dynamic(gs_text_enum_t *pte, gs_font *font)
  138. {
  139.     pte->current_font = font;
  140.     pte->index = 0;
  141.     pte->xy_index = 0;
  142.     pte->FontBBox_as_Metrics2.x = pte->FontBBox_as_Metrics2.y = 0;
  143.     return font->procs.init_fstack(pte, font);
  144. }
  145. int
  146. gs_text_enum_init(gs_text_enum_t *pte, const gs_text_enum_procs_t *procs,
  147.           gx_device *dev, gs_imager_state *pis,
  148.           const gs_text_params_t *text, gs_font *font, gx_path *path,
  149.           const gx_device_color *pdcolor, const gx_clip_path *pcpath,
  150.           gs_memory_t *mem)
  151. {
  152.     int code;
  153.  
  154.     pte->text = *text;
  155.     pte->dev = dev;
  156.     pte->pis = pis;
  157.     pte->orig_font = font;
  158.     pte->path = path;
  159.     pte->pdcolor = pdcolor;
  160.     pte->pcpath = pcpath;
  161.     pte->memory = mem;
  162.     pte->procs = procs;
  163.     /* text_begin procedure sets rc */
  164.     /* init_dynamic sets current_font */
  165.     pte->log2_scale.x = pte->log2_scale.y = 0;
  166.     /* init_dynamic sets index, xy_index, fstack */
  167.     code = gs_text_enum_init_dynamic(pte, font);
  168.     if (code >= 0)
  169.     rc_increment(dev);
  170.     return code;
  171. }
  172.  
  173. /*
  174.  * Copy the dynamically changing elements from one enumerator to another.
  175.  * This is useful primarily for enumerators that sometimes pass the
  176.  * operation to a subsidiary enumerator.
  177.  */
  178. void
  179. gs_text_enum_copy_dynamic(gs_text_enum_t *pto, const gs_text_enum_t *pfrom,
  180.               bool for_return)
  181. {
  182.     int depth = pfrom->fstack.depth;
  183.  
  184.     pto->current_font = pfrom->current_font;
  185.     pto->index = pfrom->index;
  186.     pto->xy_index = pfrom->xy_index;
  187.     pto->fstack.depth = depth;
  188.     pto->FontBBox_as_Metrics2 = pfrom->FontBBox_as_Metrics2;
  189.     if (depth >= 0)
  190.     memcpy(pto->fstack.items, pfrom->fstack.items,
  191.            (depth + 1) * sizeof(pto->fstack.items[0]));
  192.     if (for_return) {
  193.     pto->cmap_code = pfrom->cmap_code;
  194.     pto->returned = pfrom->returned;
  195.     }
  196. }
  197.  
  198. /* Begin processing text based on a graphics state. */
  199. int
  200. gs_text_begin(gs_state * pgs, const gs_text_params_t * text,
  201.           gs_memory_t * mem, gs_text_enum_t ** ppte)
  202. {
  203.     gx_clip_path *pcpath = 0;
  204.  
  205.     if (text->operation & TEXT_DO_DRAW) {
  206.     int code = gx_effective_clip_path(pgs, &pcpath);
  207.  
  208.     if (code < 0)
  209.         return code;
  210.     gx_set_dev_color(pgs);
  211.     code = gs_state_color_load(pgs);
  212.     if (code < 0)
  213.         return code;
  214.     }
  215.     return gx_device_text_begin(pgs->device, (gs_imager_state *) pgs,
  216.                 text, pgs->font, pgs->path, pgs->dev_color,
  217.                 pcpath, mem, ppte);
  218. }
  219.  
  220. /* Begin PostScript-equivalent text operations. */
  221. int
  222. gs_show_begin(gs_state * pgs, const byte * str, uint size,
  223.           gs_memory_t * mem, gs_text_enum_t ** ppte)
  224. {
  225.     gs_text_params_t text;
  226.  
  227.     text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  228.     text.data.bytes = str, text.size = size;
  229.     return gs_text_begin(pgs, &text, mem, ppte);
  230. }
  231. int
  232. gs_ashow_begin(gs_state * pgs, floatp ax, floatp ay, const byte * str, uint size,
  233.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  234. {
  235.     gs_text_params_t text;
  236.  
  237.     text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
  238.     TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  239.     text.data.bytes = str, text.size = size;
  240.     text.delta_all.x = ax;
  241.     text.delta_all.y = ay;
  242.     return gs_text_begin(pgs, &text, mem, ppte);
  243. }
  244. int
  245. gs_widthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
  246.            const byte * str, uint size,
  247.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  248. {
  249.     gs_text_params_t text;
  250.  
  251.     text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
  252.     TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  253.     text.data.bytes = str, text.size = size;
  254.     text.delta_space.x = cx;
  255.     text.delta_space.y = cy;
  256.     text.space.s_char = chr;
  257.     return gs_text_begin(pgs, &text, mem, ppte);
  258. }
  259. int
  260. gs_awidthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
  261.             floatp ax, floatp ay, const byte * str, uint size,
  262.             gs_memory_t * mem, gs_text_enum_t ** ppte)
  263. {
  264.     gs_text_params_t text;
  265.  
  266.     text.operation = TEXT_FROM_STRING |
  267.     TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
  268.     TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  269.     text.data.bytes = str, text.size = size;
  270.     text.delta_space.x = cx;
  271.     text.delta_space.y = cy;
  272.     text.space.s_char = chr;
  273.     text.delta_all.x = ax;
  274.     text.delta_all.y = ay;
  275.     return gs_text_begin(pgs, &text, mem, ppte);
  276. }
  277. int
  278. gs_kshow_begin(gs_state * pgs, const byte * str, uint size,
  279.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  280. {
  281.     gs_text_params_t text;
  282.  
  283.     text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_INTERVENE |
  284.     TEXT_RETURN_WIDTH;
  285.     text.data.bytes = str, text.size = size;
  286.     return gs_text_begin(pgs, &text, mem, ppte);
  287. }
  288. int
  289. gs_xyshow_begin(gs_state * pgs, const byte * str, uint size,
  290.         const float *x_widths, const float *y_widths,
  291.         uint widths_size, gs_memory_t * mem, gs_text_enum_t ** ppte)
  292. {
  293.     gs_text_params_t text;
  294.  
  295.     text.operation = TEXT_FROM_STRING | TEXT_REPLACE_WIDTHS |
  296.     TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  297.     text.data.bytes = str, text.size = size;
  298.     text.x_widths = x_widths;
  299.     text.y_widths = y_widths;
  300.     text.widths_size = widths_size;
  301.     return gs_text_begin(pgs, &text, mem, ppte);
  302. }
  303. int
  304. gs_glyphshow_begin(gs_state * pgs, gs_glyph glyph,
  305.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  306. {
  307.     gs_text_params_t text;
  308.  
  309.     text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
  310.     text.data.d_glyph = glyph;
  311.     text.size = 1;
  312.     return gs_text_begin(pgs, &text, mem, ppte);
  313. }
  314. int
  315. gs_cshow_begin(gs_state * pgs, const byte * str, uint size,
  316.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  317. {
  318.     gs_text_params_t text;
  319.  
  320.     text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE;
  321.     text.data.bytes = str, text.size = size;
  322.     return gs_text_begin(pgs, &text, mem, ppte);
  323. }
  324. int
  325. gs_stringwidth_begin(gs_state * pgs, const byte * str, uint size,
  326.              gs_memory_t * mem, gs_text_enum_t ** ppte)
  327. {
  328.     gs_text_params_t text;
  329.  
  330.     text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
  331.     text.data.bytes = str, text.size = size;
  332.     return gs_text_begin(pgs, &text, mem, ppte);
  333. }
  334. int
  335. gs_charpath_begin(gs_state * pgs, const byte * str, uint size, bool stroke_path,
  336.           gs_memory_t * mem, gs_text_enum_t ** ppte)
  337. {
  338.     gs_text_params_t text;
  339.  
  340.     text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
  341.     (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
  342.     text.data.bytes = str, text.size = size;
  343.     return gs_text_begin(pgs, &text, mem, ppte);
  344. }
  345. int
  346. gs_charboxpath_begin(gs_state * pgs, const byte * str, uint size,
  347.         bool stroke_path, gs_memory_t * mem, gs_text_enum_t ** ppte)
  348. {
  349.     gs_text_params_t text;
  350.  
  351.     text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
  352.     (stroke_path ? TEXT_DO_TRUE_CHARBOXPATH : TEXT_DO_FALSE_CHARBOXPATH);
  353.     text.data.bytes = str, text.size = size;
  354.     return gs_text_begin(pgs, &text, mem, ppte);
  355. }
  356. int
  357. gs_glyphpath_begin(gs_state * pgs, gs_glyph glyph, bool stroke_path,
  358.            gs_memory_t * mem, gs_text_enum_t ** ppte)
  359. {
  360.     gs_text_params_t text;
  361.  
  362.     text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_RETURN_WIDTH |
  363.     (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
  364.     text.data.d_glyph = glyph;
  365.     text.size = 1;
  366.     return gs_text_begin(pgs, &text, mem, ppte);
  367. }
  368. int
  369. gs_glyphwidth_begin(gs_state * pgs, gs_glyph glyph,
  370.             gs_memory_t * mem, gs_text_enum_t ** ppte)
  371. {
  372.     gs_text_params_t text;
  373.  
  374.     text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
  375.     text.data.d_glyph = glyph;
  376.     text.size = 1;
  377.     return gs_text_begin(pgs, &text, mem, ppte);
  378. }
  379.  
  380. /* Restart processing with different parameters. */
  381. int
  382. gs_text_restart(gs_text_enum_t *pte, const gs_text_params_t *text)
  383. {
  384.     gs_text_enum_t tenum;
  385.  
  386.     tenum = *pte;
  387.     tenum.text = *text;
  388.     gs_text_enum_init_dynamic(&tenum, pte->orig_font);
  389.     return gs_text_resync(pte, &tenum);
  390. }
  391.  
  392. /*
  393.  * Resync text processing with new parameters and string position.
  394.  */
  395. int
  396. gs_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
  397. {
  398.     return pte->procs->resync(pte, pfrom);
  399. }
  400.  
  401. /* Process text after 'begin'. */
  402. int
  403. gs_text_process(gs_text_enum_t * pte)
  404. {
  405.     return pte->procs->process(pte);
  406. }
  407.  
  408. /* Access elements of the enumerator. */
  409. gs_font *
  410. gs_text_current_font(const gs_text_enum_t *pte)
  411. {
  412.     return pte->current_font;
  413. }
  414. gs_char
  415. gs_text_current_char(const gs_text_enum_t *pte)
  416. {
  417.     return pte->returned.current_char;
  418. }
  419. gs_char
  420. gs_text_next_char(const gs_text_enum_t *pte)
  421. {
  422.     const uint operation = pte->text.operation;
  423.  
  424.     if (pte->index >= pte->text.size)
  425.     return gs_no_char;    /* rangecheck */
  426.     if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES))
  427.     return pte->text.data.bytes[pte->index];
  428.     if (operation & TEXT_FROM_CHARS)
  429.     return pte->text.data.chars[pte->index];
  430.     return gs_no_char;        /* rangecheck */
  431. }
  432. gs_glyph
  433. gs_text_current_glyph(const gs_text_enum_t *pte)
  434. {
  435.     return pte->returned.current_glyph;
  436. }
  437. int 
  438. gs_text_total_width(const gs_text_enum_t *pte, gs_point *pwidth)
  439. {
  440.     *pwidth = pte->returned.total_width;
  441.     return 0;
  442. }
  443.  
  444. /* Assuming REPLACE_WIDTHS is set, return the width of the i'th character. */
  445. int
  446. gs_text_replaced_width(const gs_text_params_t *text, uint index,
  447.                gs_point *pwidth)
  448. {
  449.     const float *x_widths = text->x_widths;
  450.     const float *y_widths = text->y_widths;
  451.  
  452.     if (index > text->size)
  453.     return_error(gs_error_rangecheck);
  454.     if (x_widths == y_widths) {
  455.     if (x_widths) {
  456.         index *= 2;
  457.         pwidth->x = x_widths[index];
  458.         pwidth->y = x_widths[index + 1];
  459.     }
  460.     else
  461.         pwidth->x = pwidth->y = 0;
  462.     } else {
  463.     pwidth->x = (x_widths ? x_widths[index] : 0.0);
  464.     pwidth->y = (y_widths ? y_widths[index] : 0.0);
  465.     }
  466.     return 0;
  467. }
  468.  
  469. /* Determine whether only the width is needed. */
  470. bool
  471. gs_text_is_width_only(const gs_text_enum_t * pte)
  472. {
  473.     return pte->procs->is_width_only(pte);
  474. }
  475.  
  476. /* Return the width of the current character. */
  477. int
  478. gs_text_current_width(const gs_text_enum_t * pte, gs_point *pwidth)
  479. {
  480.     return pte->procs->current_width(pte, pwidth);
  481. }
  482.  
  483. /* Set text metrics and optionally enable caching. */
  484. int
  485. gs_text_set_cache(gs_text_enum_t * pte, const double *values,
  486.           gs_text_cache_control_t control)
  487. {
  488.     return pte->procs->set_cache(pte, values, control);
  489. }
  490. int
  491. gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
  492. {
  493.     return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
  494. }
  495. int
  496. gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
  497. {
  498.     return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
  499. }
  500. int
  501. gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
  502. {
  503.     return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
  504. }
  505.  
  506. /* Retry processing the last character without caching. */
  507. int
  508. gs_text_retry(gs_text_enum_t * pte)
  509. {
  510.     return pte->procs->retry(pte);
  511. }
  512.  
  513. /* Release the text processing structures. */
  514. void
  515. gx_default_text_release(gs_text_enum_t *pte, client_name_t cname)
  516. {
  517.     rc_decrement_only(pte->dev, cname);
  518. }
  519. void
  520. rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
  521. {
  522.     gs_text_enum_t *pte = obj;
  523.  
  524.     pte->procs->release(pte, cname);
  525.     rc_free_struct_only(mem, obj, cname);
  526. }
  527. void
  528. gs_text_release(gs_text_enum_t * pte, client_name_t cname)
  529. {
  530.     rc_decrement_only(pte, cname);
  531. }
  532.  
  533. /* ---------------- Default font rendering procedures ---------------- */
  534.  
  535. /* Default fstack initialization procedure. */
  536. int
  537. gs_default_init_fstack(gs_text_enum_t *pte, gs_font *pfont)
  538. {
  539.     pte->fstack.depth = -1;
  540.     return 0;
  541. }
  542.  
  543. /* Default next-glyph procedure. */
  544. int
  545. gs_default_next_char_glyph(gs_text_enum_t *pte, gs_char *pchr, gs_glyph *pglyph)
  546. {
  547.     if (pte->index >= pte->text.size)
  548.     return 2;
  549.     if (pte->text.operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
  550.     /* ordinary string */
  551.     *pchr = pte->text.data.bytes[pte->index];
  552.     *pglyph = gs_no_glyph;
  553.     } else if (pte->text.operation & TEXT_FROM_SINGLE_GLYPH) {
  554.     /* glyphshow or glyphpath */
  555.     *pchr = gs_no_char;
  556.     *pglyph = pte->text.data.d_glyph;
  557.     } else if (pte->text.operation & TEXT_FROM_GLYPHS) {
  558.     *pchr = gs_no_char;
  559.     *pglyph = pte->text.data.glyphs[pte->index];
  560.     } else if (pte->text.operation & TEXT_FROM_SINGLE_CHAR) {
  561.     *pchr = pte->text.data.d_char;
  562.     *pglyph = gs_no_glyph;
  563.     } else if (pte->text.operation & TEXT_FROM_CHARS) {
  564.     *pchr = pte->text.data.chars[pte->index];
  565.     *pglyph = gs_no_glyph;
  566.     } else
  567.     return_error(gs_error_rangecheck); /* shouldn't happen */
  568.     pte->index++;
  569.     return 0;
  570. }
  571.  
  572. /* Dummy (ineffective) BuildChar/BuildGlyph procedure */
  573. int
  574. gs_no_build_char(gs_text_enum_t *pte, gs_state *pgs, gs_font *pfont,
  575.          gs_char chr, gs_glyph glyph)
  576. {
  577.     return 1;            /* failure, but not error */
  578. }
  579.